package cc.laop.utils;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;

public class SecretUtils {

    /**
     * 加密
     *
     * @param key
     * @param content
     * @return
     * @throws Exception
     */
    public static String encrypt(String key, String content,
                                 Algorithm algorithm) throws Exception {
        byte[] keyByte = hex(key, algorithm);
        byte[] encryptContent = encrypt(keyByte, content.getBytes(), algorithm);
        return Base64.encodeBase64String(encryptContent);
    }

    /**
     * 解密
     *
     * @param key
     * @param content
     * @return
     * @throws Exception
     */
    public static String decrypt(String key, String content,
                                 Algorithm algorithm) throws Exception {
        byte[] encryptContent = Base64.decodeBase64(content);
        byte[] keyByte = hex(key, algorithm);
        byte[] decryptContent = decrypt(keyByte, encryptContent, algorithm);
        return new String(decryptContent);
    }

    /**
     * 加密方法
     *
     * @param keybyte 加密密钥
     * @param src     被加密的数据缓冲区（源）
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] keybyte, byte[] src,
                                 Algorithm algorithm) throws Exception {
        // 生成密钥
        SecretKey deskey = new SecretKeySpec(keybyte, algorithm.getValue());
        // 加密
        Cipher c1 = Cipher.getInstance(algorithm.getValue());
        c1.init(Cipher.ENCRYPT_MODE, deskey);
        return c1.doFinal(src);
    }

    /**
     * 解密
     *
     * @param keybyte 加密密钥
     * @param src     加密后的缓冲区
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] keybyte, byte[] src,
                                 Algorithm algorithm) throws Exception {
        // 生成密钥
        SecretKey deskey = new SecretKeySpec(keybyte, algorithm.getValue());
        // 解密
        Cipher c1 = Cipher.getInstance(algorithm.getValue());
        c1.init(Cipher.DECRYPT_MODE, deskey);
        return c1.doFinal(src);
    }

    /**
     * 处理密钥长度 <br>
     * AES 取key的MD5（16位）<br>
     * DES 截取key的MD5（16位）前8位 <br>
     * 3DES 截取key的MD5（32位）前24位
     *
     * @param key
     * @param algorithm
     * @return
     * @throws UnsupportedEncodingException
     */
    private static byte[] hex(String key, Algorithm algorithm)
            throws UnsupportedEncodingException {
        key = DigestUtils.md5Hex(key);
        String rawKey;
        switch (algorithm) {
            case AES:
                rawKey = key.substring(0, 16);
                break;
            case DES:
                rawKey = key.substring(0, 8);
                break;
            case DESede:
                rawKey = key.substring(0, 24);
                break;
            default:
                rawKey = key;
                break;
        }
        return rawKey.getBytes();
    }

    /**
     * 加密算法
     *
     * @author Pengpeng
     */
    public enum Algorithm {

        AES("AES"), DES("DES"), DESede("DESede");

        private String value;

        Algorithm(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }

    }

}
